﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace BoneSystem.Extensions
{
    public class FocusManager
    {
        private string DefaultFormName
        {
            get
            {
                if (string.IsNullOrEmpty(_defaultFormName))
                {
                    _defaultFormName = "defaultForm";
                    FormList.Add(0, new FocusManagerForm());
                }
                return _defaultFormName;
            }
            set { _defaultFormName = value; }
        }

        private  Dictionary<int, FocusManagerItem> _focusList;
        private  Dictionary<int, FocusManagerForm> _formList;
        private  string _defaultFormName = null;

        private  Dictionary<int, FocusManagerForm> FormList
        {
            get { return _formList ?? (_formList = new Dictionary<int, FocusManagerForm>()); }
            set { _formList = value; }
        }

        private  Dictionary<int, FocusManagerItem> FocusList
        {
            get { return _focusList ?? (_focusList = new Dictionary<int, FocusManagerItem>()); }
            set { _focusList = value; }
        }

        private static FocusManagerItem FirstItem { get; set; }

        /// <summary>
        /// Gera o javascript para tabulação.
        /// </summary>
        /// <param name="formName">Formulario que deseja fechar se nada for especificado no parâmetro
        /// então é gerado o script com todos os formulários contidos na lista de foco.</param>
        /// <returns></returns>
        public  HtmlString End(string formName = "")
        {
            var build = new StringBuilder();
            //build.Attributes["type"] = "text/javascript";
            //build.Attributes["language"] = "javascript";
            var initComponent = "";
            foreach (var form in FormList)
            {
                // Varre os itens do formulário para adicionar os eventos.
                for (int i = 0; i < form.Value.FocusManagerItems.OrderBy(x => x.Key).Select(x => x).Count(); i++)
                {
                    var nextIndexField = -1;
                    FocusManagerItem nextItem = null;
                    FocusManagerItem currentItem = null;
                    
                    var maxIndex = form.Value.FocusManagerItems.Max(x => x.Key);
                    var currentIndex = i;
                    do
                    {
                        currentIndex += 1;
                        // Caso o indice procurado exista na lista então passa para
                        if (form.Value.FocusManagerItems.ContainsKey(currentIndex))
                        {
                            nextIndexField = currentIndex;
                        }
                        else
                        {
                            if (currentIndex == maxIndex)
                            {
                                nextIndexField = form.Value.FocusManagerItems.Keys.OrderBy(x => x).First(); //(x=>x.Key).FirstOrDefault();
                            }
                        }
                       
                    } while (nextIndexField == -1);



                    // Pega o componente que irá receber o foco após o atual.
                    form.Value.FocusManagerItems.TryGetValue(nextIndexField, out nextItem);
                    // Pega o componente atual.
                    form.Value.FocusManagerItems.TryGetValue(i, out currentItem);
                    if (currentItem != null && string.IsNullOrEmpty(initComponent))
                    {
                        initComponent = currentItem.ControlId;
                    }
                    // Adiciona o comportamento de foco para o chamar o foco no próximo componente.
                    if (nextItem != null && currentItem != null)
                    {
                        build.Append(@"$('#" + currentItem.ControlId + "').keyup(function(e) {   if(e.keyCode == 13) { $('#" + nextItem.ControlId + "').focus();}});");
                        if (i == form.Value.FocusManagerItems.Count -1)
                        {
                            build.Append(@"$('#" + nextItem.ControlId + "').keyup(function(e) {   if(e.keyCode == 13) { $('#" + initComponent + "').focus();}});");
                            build.Append(@"$('#" + initComponent + "').focus();");
                        }
                    }
                    
                }
            }
            return new HtmlString( build.ToString() );
        }

        public static void Start()
        {

        }
        /// <summary>
        /// Seta o formulário padrão atual, ou seja, caso não seja informado na adição de um item no controle
        /// de foco o FocusManager adicionará o item ao formulário indicado neste método.
        /// </summary>
        /// <param name="formName"></param>
        public  void SetDefaultForm(string formName)
        {
            DefaultFormName = formName;
        }



        /// <summary>
        /// Adicionar um novo item ao FocusManager.
        /// </summary>
        /// <param name="settings">Item a ser adicionado ao FocusManager</param>
        public  void AddFocusItem(Settings settings)
        {
            if (settings.Focused)
            {
                AddFocusItem(new FocusManagerItem()
                {
                    ControlId = settings.Name
                }, settings.ParentFormName);
            }

        }

        public  void AddFocusItem(FocusManagerItem item, string formName = "")
        {

            if (formName == null || formName.Equals(""))
            {
                formName = DefaultFormName;
                var selectedform = FormList.Values.SingleOrDefault(x => x.FormName == formName);
                if (selectedform == null)
                {
                    var indexForm = FormList.Keys.Max(x => x) + 1;
                    FormList.Add(indexForm, new FocusManagerForm()
                    {
                        FormName = formName
                    });
                }
            }

            var form = FormList.Values.FirstOrDefault(x => x.FormName == formName);

            if (form != null)
            {
                form.AddFocusItem(item);
            }

            int index = 0;
            // Obtém o indice do próximo item.
            if (FocusList.Count > 0)
            {
                index = FocusList.Keys.Max(x => x) + 1;
            }

            FocusList.Add(index, item);

            if (FirstItem == null)
            {
                FirstItem = item;
            }
        }
    }
    public class FocusManagerForm
    {
        private Dictionary<int, FocusManagerItem> _focusManagerItems;
        public string FormName { get; set; }

        public Dictionary<int, FocusManagerItem> FocusManagerItems
        {
            get { return _focusManagerItems ?? (_focusManagerItems = new Dictionary<int, FocusManagerItem>()); }
            set { _focusManagerItems = value; }
        }

        public void AddFocusItem(FocusManagerItem item)
        {
            int index = 1;
            // Obtém o indice do próximo item.
            if (FocusManagerItems.Count > 0)
            {
                index = FocusManagerItems.Keys.Max(x => x) + 1;
            }

            FocusManagerItems.Add(index, item);
        }
    }

    public class FocusManagerItem
    {
        public FocusManagerForm FocusManagerForm { get; set; }
        public string ControlId { get; set; }

        // override object.Equals
        public override bool Equals(object obj)
        {
            var item = obj as FocusManagerItem;
            if (item != null)
            {
                if (item.ControlId.Equals(ControlId) &&
                    item.FocusManagerForm.FormName.Equals(FocusManagerForm.FormName))
                {
                    return true;
                }
            }
            return false;
        }

    }

}